// service/cleaner/cleaner.go

package internal

import (
	"time"
	"yunpan/db"
	"yunpan/logger"
	"yunpan/pool"
	"yunpan/store/ceph"

	"go.uber.org/zap"
)

type TrashCleaner struct {
	dbPool     *pool.DBWorkerPool
	cephPool   *pool.CephWorkerPool
	stopChan   chan struct{}
	interval   time.Duration
	retainDays int
	batchSize  int
}

func NewTrashCleaner(dbPool *pool.DBWorkerPool, cephPool *pool.CephWorkerPool,
	interval time.Duration, retainDays, batchSize int) *TrashCleaner {
	return &TrashCleaner{
		dbPool:     dbPool,
		cephPool:   cephPool,
		stopChan:   make(chan struct{}),
		interval:   interval,
		retainDays: retainDays,
		batchSize:  batchSize,
	}
}

func (tc *TrashCleaner) cleanExpiredFiles() {
    startTime := time.Now()
    logger.Info("Starting cleanup task",
        zap.Time("startTime", startTime))

    dbTask := pool.NewDBTask(
        "清理过期文件",
        3,
        func() error {
            expireTime := time.Now().AddDate(0, 0, -tc.retainDays)
            logger.Info("Calculating expired files",
                zap.Time("expireTime", expireTime))

            var totalProcessed int
            var totalDeleted int

            for {
                // 分批获取过期文件
                expiredFiles, err := db.GetExpiredFilesBatch(expireTime, tc.batchSize, totalProcessed)
                if err != nil {
                    logger.Error("Failed to get expired files",
                        zap.Error(err))
                    return err
                }

                if len(expiredFiles) == 0 {
                    break
                }

                logger.Info("Processing batch",
                    zap.Int("batchSize", len(expiredFiles)),
                    zap.Int("totalProcessed", totalProcessed))

                // 处理这一批文件
                for _, file := range expiredFiles {
                    if !file.IsOriginal {
                        // 快捷方式：只需要删除数据库记录并减少源文件引用计数
                        if _,err = db.DeleteShortcut(file.UserName, file.FileHash); err != nil {
                            logger.Error("Failed to delete shortcut",
                                zap.String("fileName", file.FileName),
                                zap.Error(err))
                            continue
                        }
                        totalDeleted++
                        logger.Info("Shortcut deleted successfully",
                            zap.String("fileName", file.FileName),
                            zap.String("fileHash", file.FileHash))
                    } else {
                        // 源文件：检查引用计数
                        if file.ReferenceCount > 1 {
                            // 如果还有其他引用，减少引用计数并更新状态
                            if err := db.DecrementReferenceAndUpdateStatus(file.UserName, file.FileHash); err != nil {
                                logger.Error("Failed to update reference count and status",
                                    zap.String("fileName", file.FileName),
                                    zap.Error(err))
                                continue
                            }
                            totalDeleted++
                            logger.Info("Original file reference updated",
                                zap.String("fileName", file.FileName),
                                zap.String("fileHash", file.FileHash))
                            continue
                        }

                        // 引用计数为1，执行完整的删除流程
                        cephTask := pool.NewCephTask(
                            file.UserName,
                            "删除过期文件",
                            3,
                            func(conn *ceph.StorageSession) error {
                                fullPath := file.ParentPath + file.FileName
                                if file.IsFolder {
                                    fullPath += "/"
                                }
                                if fullPath[0] == '/' {
                                    fullPath = fullPath[1:]
                                }
                                return conn.DeleteObject(fullPath)
                            },
                        )

                        if err := tc.cephPool.Submit(cephTask); err != nil {
                            logger.Error("Failed to submit Ceph delete task",
                                zap.String("fileName", file.FileName),
                                zap.Error(err))
                            continue
                        }

                        if err := cephTask.Wait(); err != nil {
                            logger.Error("Failed to delete file from Ceph",
                                zap.String("fileName", file.FileName),
                                zap.Error(err))
                            continue
                        }

                        if err := db.PermanentlyDeleteFile(file.FileHash); err != nil {
                            logger.Error("Failed to delete file from database",
                                zap.String("fileName", file.FileName),
                                zap.Error(err))
                            continue
                        }

                        totalDeleted++
                        logger.Info("Original file deleted successfully",
                            zap.String("fileName", file.FileName),
                            zap.String("fileHash", file.FileHash),
                            zap.Int64("fileSize", file.FileSize))
                    }
                    totalProcessed++
                }
            }

            duration := time.Since(startTime)
            logger.Info("Cleanup task completed",
                zap.Duration("duration", duration),
                zap.Int("totalProcessed", totalProcessed),
                zap.Int("totalDeleted", totalDeleted))

            return nil
        },
    )

    if err := tc.dbPool.Submit(dbTask); err != nil {
        logger.Error("Failed to submit cleanup task",
            zap.Error(err))
    }
}

// Start 启动清理服务
func (tc *TrashCleaner) Start() {
	logger.Info("Starting trash cleaner service",
		zap.Duration("interval", tc.interval),
		zap.Int("retainDays", tc.retainDays),
		zap.Int("batchSize", tc.batchSize))

	go func() {
		// 立即执行一次清理
		tc.cleanExpiredFiles()

		// 创建定时器
		ticker := time.NewTicker(tc.interval)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				tc.cleanExpiredFiles()
			case <-tc.stopChan:
				logger.Info("Trash cleaner service stopped")
				return
			}
		}
	}()
}

// Stop 停止清理服务
func (tc *TrashCleaner) Stop() {
	logger.Info("Stopping trash cleaner service")
	close(tc.stopChan)
}

// IsRunning 检查服务是否正在运行
func (tc *TrashCleaner) IsRunning() bool {
	select {
	case <-tc.stopChan:
		return false
	default:
		return true
	}
}
